/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.rie06.openvoip.server;

import com.rie06.openvoip.User;
import com.rie06.openvoip.client.Conversation;
import java.io.*;
import java.net.Socket;
import java.util.UUID;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 *
 * @author clement
 */
public class ServerTCPThread implements Runnable {

    private User user;
    //Server Info
    private Server server;
    //TCP Input / Output
    private Socket socket;
    private ObjectInput inputTCP;
    private ObjectOutput outputTCP;
    //Thread
    private Thread thread;
    private static final Logger logger = Logger.getLogger(ServerTCPThread.class);

    public ServerTCPThread(Server server, Socket socket) {
        try {
            logger.log(Level.DEBUG, "New connection on port: " + server.getPort());
            this.server = server;
            this.socket = socket;

            inputTCP = new ObjectInputStream(socket.getInputStream());
            outputTCP = new ObjectOutputStream(socket.getOutputStream());
            outputTCP.flush();

            ServerMessage smIn = (ServerMessage) inputTCP.readObject();
            if (!smIn.getType().equals("uuid")) {
                logger.log(Level.FATAL, "Need to have an UUID");
                throw new IllegalArgumentException("Need to have an UUID");
            }

            //send UUID
            ServerMessage smOut = new ServerMessage("uuid", server.getServerConfig().getUserName(), server.getServerConfig().getId());
            outputTCP.writeObject(smOut);
            outputTCP.flush();

            //get UUID
            UUID id = smIn.getFrom();

            user = new User(id, (String) smIn.getMessage());
            user.setIpAddress(socket.getInetAddress());
            user.setServerTCPThread(this);

            server.getUsersList().put(user.getId(), user);

            logger.log(Level.DEBUG, "User '" + user.getUserName() + "' add in Server:usersList : Size: " + server.getUsersList().size());

            //send User to Client or IHM
            //server.getIhm().getListContactCall().add(new Contact(user.getUserName(), socket.getInetAddress()));
            //server.getIhm().getListContact().updateListContact();

            thread = new Thread(this);
            thread.start();

        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(ServerTCPThread.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IOException ex) {
            logger.log(Level.FATAL, ex);
        }

    }

    public ServerTCPThread(Server server, Socket socket, ObjectInput inputTCP, ObjectOutput outputTCP, User user) {
        this.server = server;
        this.socket = socket;
        this.inputTCP = inputTCP;
        this.outputTCP = outputTCP;
        this.user = user;


        this.user.setIpAddress(socket.getInetAddress());
        this.user.setServerTCPThread(this);
        server.getUsersList().put(this.user.getId(), this.user);

        logger.log(Level.DEBUG, "User '" + user.getUserName() + "' add in Server:usersList : Size: " + server.getUsersList().size());

        thread = new Thread(this);
        thread.start();

    }

    public int sendMessage(ServerMessage sm) {
        try {
            outputTCP.writeObject(sm);
        } catch (IOException ex) {
            java.util.logging.Logger.getLogger(ServerTCPThread.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            return 404;
        }
        return 200;
    }

    private enum Command {

        uuid, message, addcontact, conversation, call, close, novalue;

        public static Command fromString(String Str) {
            try {
                return valueOf(Str);
            } catch (Exception ex) {
                return novalue;
            }
        }
    };

    public Socket getSocket() {
        return socket;
    }

    public void run() {

        while (thread != null) {
            try {
                //wait input
                logger.log(Level.DEBUG, "Wait Command from " + user.getUserName());

                ServerMessage smIn = (ServerMessage) inputTCP.readObject();

                switch (Command.fromString(smIn.getType())) {
                    case uuid:
                        break;
                    case message:
                        logger.log(Level.DEBUG, "Server receive from <" + user.getUserName() + "> message: " + smIn.getMessage());
                        break;
                    case addcontact:
                        logger.log(Level.DEBUG, "Server receive from <" + user.getUserName() + "> : AddContact");
                        server.getClient().addContactToList(user.getId(), user.getUserName(), user.getIpAddress(), 1995);
                        break;
                    case conversation:
                        //0 = request
                        //1 = Send ContactList
                        //2 = add Contact
                        //-2 = delete Contact
                        //3 = contact accept call
                        //-3 = contact set pause
                        //4 = send message
                        ServerMessage_Conversation smc = (ServerMessage_Conversation) smIn;
                        switch ((Integer) smc.getMessage()) {
                            case 0:
                                logger.log(Level.DEBUG, "Request conversation from : " + user.getUserName());
                                server.getClient().addConversation(smc.getConversationUUID(), user);
                                break;
                            case 1:
                                logger.log(Level.DEBUG, "Request contactList Updated from : " + user.getUserName());
                                Conversation c0 = (Conversation) server.getClient().getConversationList().get(smc.getConversationUUID());
                                c0.updateContactList(smc.getContactList(), smc.getContactListCall(), smc.isMasterPause());
                                break;
                            case 2:
                                break;
                            case -2:
                                logger.log(Level.DEBUG, "Request disconect from : " + user.getUserName());
                                Conversation c3 = (Conversation) server.getClient().getConversationList().get(smc.getConversationUUID());
                                c3.setCloseConversation(user.getId());
                                break;
                            case 3:
                                logger.log(Level.DEBUG, "An user set Play(): " + user.getUserName() + " - " + smc.getConversationUUID());
                                Conversation c1 = (Conversation) server.getClient().getConversationList().get(smc.getConversationUUID());
                                c1.setPlay(user.getId());
                                break;
                            case -3:
                                logger.log(Level.DEBUG, "An user set Pause(): " + user.getUserName());
                                Conversation c2 = (Conversation) server.getClient().getConversationList().get(smc.getConversationUUID());
                                c2.setPause(user.getId());
                                break;
                            case 4:
                                logger.log(Level.DEBUG, "An user send a Message(): " + user.getUserName());
                                Conversation c4 = (Conversation) server.getClient().getConversationList().get(smc.getConversationUUID());
                                c4.receiveMessage(smc.getText());
                                break;
                            default:
                                logger.log(Level.ERROR, "Unrecognized message: " + smIn.getMessage().toString());
                                break;
                        }
                        break;
                    case call:
                        break;
                    case close:
                        logger.log(Level.INFO, "User Quit: " + user.getUserName());
                        ServerMessage sm = new ServerMessage("close", null, server.getServerConfig().getId());
                        sendMessage(sm);
                        thread = null;
                        break;
                    case novalue:
                        logger.log(Level.ERROR, "Unrecognized command: " + smIn.getType());
                }

            } catch (EOFException ex) {
                server.getUsersList().remove(user.getId());
                //Delete conversation if exist

                thread = null;
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(ServerTCPThread.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IOException ex) {
                java.util.logging.Logger.getLogger(ServerTCPThread.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            }
        }

        logger.log(Level.INFO, "Delete User <" + user.getUserName() + "> from serverUsersList");
        server.getUsersList().remove(user.getId());
    }
}
